package playn.platformer;

import java.util.HashMap;

import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.World;

import playn.core.CanvasImage;
import playn.core.Font;
import playn.core.Image;
import playn.core.ImageLayer;
import playn.core.ImmediateLayer;
import playn.core.PlayN;
import playn.core.SurfaceLayer;
import playn.core.TextFormat;
import playn.core.TextLayout;
import tiled.simple.core.Map;
import tiled.simple.core.ObjectGroup;
import playn.platformer.Camera;
import playn.platformer.Controls;
import playn.platformer.FPSCounter;
import playn.platformer.GameContactListener;
import playn.platformer.MapObjectsProvider;
import playn.platformer.StaticRenderer;
import playn.platformer.MapShapesProvider;

import static playn.core.PlayN.*;


public class Game implements playn.core.Game {
	
	public static final float PIXEL_PER_METER=500;
 	
	private Map map;
	
	public Map animationGraphics;
	public ObjectGroup animations;

	
	public World world;
	private MapShapesProvider mapShapesProvider;
	private MapObjectsProvider mapObjectsProvider;

	public Camera camera=new Camera();
	public StaticRenderer staticRenderer;
	public DynamicRenderer dynamicRenderer;

	public GameContactListener contactListener;
	
	public Controls controls=new Controls();
	
	// for FPS
	private FPSCounter fps=new FPSCounter();
	private ImageLayer statisticsLayer;
	private TextLayout fpsTextLayout=null;
	
	public Game(HashMap<String,Map> maps,Controls controls, HashMap<String, Image> imagesCache){
		
		this.staticRenderer=new StaticRenderer(imagesCache);
		this.controls=controls;
		this.map=maps.get("/level.tmx");
		this.animationGraphics=maps.get("/graphics.tmx");
		this.animations=animationGraphics.getObjectGroup("animations");
		
		boolean doSleep = true;
		Vec2 gravity = new Vec2(0.0f, 10.0f);
		this.world = new World(gravity,doSleep);
		
		this.contactListener = new GameContactListener();
		world.setContactListener(contactListener);
		
		mapShapesProvider = new MapShapesProvider(this.world);
		mapObjectsProvider = new MapObjectsProvider(this);
		
		dynamicRenderer=new DynamicRenderer(mapObjectsProvider,imagesCache);
		
		map.getObjectGroup("collision").loadShapes(mapShapesProvider);
		map.getObjectGroup("entities").loadObjects(mapObjectsProvider);
		
		map.getLayer("layer1").setPriority(1);
		map.getLayer("layer2").setPriority(2);

	}
	
	SurfaceLayer staticLayer;
	ImmediateLayer dynamicLayer;

	@Override
	public void init() {
		staticLayer=graphics().createSurfaceLayer(map.getWidth()*map.getTileWidth(), map.getHeight()*map.getTileHeight());
		dynamicLayer=graphics().createImmediateLayer(map.getWidth()*map.getTileWidth(), map.getHeight()*map.getTileHeight(),dynamicRenderer);
		
		int width=graphics().screenWidth();
		int height=graphics().screenHeight();

		graphics().setSize(width, height);
		
		staticRenderer.layer=staticLayer;

		map.render(staticRenderer);
		
		
		graphics().rootLayer().add(staticLayer);
		graphics().rootLayer().add(dynamicLayer);
		keyboard().setListener(controls);
		
		// for FPS
		statisticsLayer=graphics().createImageLayer();
		graphics().rootLayer().add(statisticsLayer);
		
		
		PlayN.log().info("init done");
	}

	@Override
	public void update(float delta) {
		world.step((float)delta/1000, 100, 100);
		mapObjectsProvider.update(delta);
		camera.update();
	}

	@Override
	public void paint(float alpha) {
		staticLayer.setTranslation( ((graphics().width())/2-camera.X()), ((graphics().height()/2-camera.Y())) );
		dynamicLayer.setTranslation( ((graphics().width())/2-camera.X()), ((graphics().height()/2-camera.Y())) );
		
		fps.frame();
		
		// for FPS
		Font font = graphics().createFont("Times", Font.Style.BOLD, 24f);
        TextFormat format = new TextFormat().withFont(font);
		fpsTextLayout=graphics().layoutText("FPS="+fps.get(), format);

		CanvasImage c=graphics().createImage(100, 100);
		c.canvas().setFillColor(0xFFFFFFFF);
		c.canvas().fillText(fpsTextLayout, 10f, 10f);
		statisticsLayer.setImage(c);
	}

	@Override
	public int updateRate() {
		return 15;
	}

}
